/*==============================================================*/
/* program: freetree.c                                          */
/* purpose: generating all free trees                           */
/* input  : n -- number of nodes                                */
/*          m -- max degree                                     */
/*          lb,ub -- lower and upper bound on diameter          */
/* output : listing of free trees in relex order                */
/* date   : September 1995, updated Sept 2000                   */
/* programmers: Gang Li & Frank Ruskey                          */
/* algorithm: From the paper: G. Li and F. Ruskey,  "The        */
/*    Advantages of Forward Thinking in Generating Rooted and   */
/*    Free Trees",  10th Annual ACM-SIAM Symposium on Discrete  */
/*    Algorithms (SODA), (1999) S939-940.  See the web page at  */
/*    http://www.theory.csc.UVic.CA/~fruskey/                   */
/*      Publications/RootedFreeTree.html                        */
/* more info: See                                               */
/*    http://www.theory.csc.UVic.CA/inf/FreeTrees.html     */
/*==============================================================*/

#include <stdio.h>
#include <iostream>
using namespace std;

#define MAX_SIZE   50  /* max size of the tree */
#define TRUE        1
#define FALSE       0

int
 par[MAX_SIZE],                 /* parent position of i  */
 L[MAX_SIZE],                   /* level of node i       */
 k,                             /* max number of children */
 chi[MAX_SIZE],                 /* number of children of a node */
 nextp[MAX_SIZE],               /* next good pos to add nodes */
 rChi[MAX_SIZE],                /* the right most child of node i */
 ub;                            /* upper bound           */
unsigned int num;               /* number of trees */

int N;  /* Corresponds to -n */
int K;  /*                -k */
int M;            /*      -m */
int U;            /*      -u */

const int maxN = 30;     // Code added by W. Bomfim
unsigned __int64 an;    // a(n)
int Pai[maxN + 1];     // Copy of par,
unsigned int Deg[maxN+1], D[maxN+1];   // Deg[i], 1<=i<=N, is the degree of i.

bool IsApath(){
static int i;
for(i=1; i<=N; i++)
    if(Deg[i]>2)// the tree is not a path if the degree of a node is > 2.
        return false;
return true;
}

void TestLobster(){
static unsigned int i, k, j, V[maxN]; // j, V is a list of leaves
for(i=1; i <= N; i++) // Save degrees
    D[i] = Deg[i];
if(Deg[1] == 1){
    printf("root is a live. Press Enter"); getchar();
    }
j = 0;
for(i=2; i <= N; i++)
    if(Deg[i]==1){
        k = Pai[i];
        Deg[k]--;
        if(Deg[k] == 1){// new leaf?
            V[j] = k; j++;
            }
        }
for(i=0; i < j; i++)
    Deg[Pai[V[i]]]--;
if(IsApath())
    an++;
for(i=1; i <= N; i++)// Restaure degrees
    Deg[i] = D[i];
}

void initialize(){
/*
    The degree of an internal node i is one plus the number of children of i.
The degree of the root (1) is the number of children of 1. This number is
equal to the number of times that i (or 1) appears in the parent array Pai.
*/
static int i;
an = 0;
for(i=1; i<=N; i++){
    Pai[i] = par[i];
    Deg[i] = 1;
    }
for(i=1; i<=N; i++)
    Deg[Pai[i]]++;
Deg[1]--;           // The root 1 do not have a father.
TestLobster();
}

void PrintIt() {
static int i, k, L;
num = num+1;
if(num == 1){
    initialize(); return; }
for(i=3; i<=N; i++)
    if(par[i] != Pai[i]){
        L = Pai[i];
        Deg[L]--;
        L = par[i];
        Deg[L]++;
        Pai[i] = par[i];
        }
TestLobster();
}// End of code added by W. Bomfim

void updateL() {
    int i;
    L[1]=0;
    for ( i=2; i<=N; ++i ) L[i] = L[par[i]]+1;
}

int good( int p, int h, int t ) {
  if (p==2 && K<=2 && t==0) return TRUE;
  if (t == 1) {
     if (2*h>=K+1 && 2*h <= U+1) {
        if ((p-1)*2 >= N) return TRUE;
        else if (p - h-1 == 1) {
          if (par[p]> 2) return TRUE;
        } else
          if ((p - h-1 >=2) && ((par[h+2]>2) || (par[h+3]>2))) return TRUE;
     }
  } else
  if (N-p >= h && 2*h>=K) {
     if (U==N-1 && N%2==0) return(2*h<=U+1);
     else return(2*h <= U);
  }
  return FALSE;
} /* good */

void Gen( int p, int s, int cL, int h, int l, int n, int f, int g ) {
  int hh,flag,entry,temp;
  if (p > n)
     if (f == 0) {
        if (good(p-1,h,0)) Gen(p, 2, p-2,h,n,N,1,0);
        if (good(p-1,h,1)) Gen(p, 2, p-3,h,n,N,1,1);
     } else { updateL(); PrintIt();}
  else {
     if (cL == 0) {
        if ( p< ub+2 ) par[p] = p-1;
        else {
           Gen( p, p-1, 1, h, l, n, f, g );
           return;
        }
     } else
        if (par[p-cL] < s) par[p]=par[p-cL];
        else {
           par[p] = cL + par[p-cL];
           if (g==1)
               if (((l-1)*2 < n) && (p-cL<=l) && (
                   ((p-cL+1<l) &&  (par[p-cL+1]==2)
                   && (p-cL+2<=l) && (par[p-cL+2]==2))     /*case 1*/
                   || ((p-cL+1==l) && (par[p-cL+1]==2))    /*case 2*/
                   || (p-cL+1>l))) {                       /*case 3*/
                  s= par[p]; cL= p-s;
                  par[p] = par[par[p]];
               } else
                  if (par[p-cL]==2) par[p]=1;
        }
        if (s!=0 || p<=ub+1) {
           chi[par[p]] = chi[par[p]] + 1;
           temp = rChi[par[p]]; rChi[par[p]] = p;
           if (chi[par[p]] <= ((par[p]==1)?k:k-1)) {
              if (chi[par[p]] < (par[p]==1?k:k-1)) nextp[p] = par[p];
              else nextp[p] = nextp[par[p]];
              Gen( p+1, s, cL,h,l,n,f,g );
           }
           chi[par[p]] = chi[par[p]] - 1;
           rChi[par[p]] = temp;
        }
        if (s==0 && 2*(p-2)<K) return;

        nextp[p] = nextp[par[p]];
        entry = nextp[p];
        flag= 0; hh=1;
        while ((((f==0) && (entry>=2)) ||
	       ((f==1) && (entry>=1))) && (flag==0)) {
           if (s==0) h = p-2;
           if (p<=l+h-g) hh = 0;
           if ((f==0) || (hh==1)) {
              /*s = par[p]; par[p] = par[s];*/
              par[p] = entry;

              chi[entry] = chi[entry] + 1;
	      temp = rChi[par[p]];  rChi[par[p]] = p;
	      if (chi[entry] >= (entry==1?k:k-1)) nextp[p] = nextp[entry];
              if (f == 0) Gen(p+1,temp,p-temp,h,0,N-h+1,f,g);
              else if (hh == 1) Gen(p+1,temp,p-temp,h,l,n,f,g);
	      chi[entry] = chi[entry] - 1;
	      rChi[par[p]] = temp;
	      entry = nextp[entry];
	      nextp[p] = entry;
           } else flag= 1;
        }
        if (f == 0) {
           if (good(p-1,h,0)) Gen(p,2,p-2,h,p-1,N,1,0);
           if (good(p-1,h,1)) Gen(p,2,p-3,h,p-1,N,1,1);
        }
  }
} /* Gen */

main() {                // code modified by W. Bomfim
int i;
K = 2;
par[1] = 0; par[2] = 1;
for(N = 1; N <= maxN; N++){
    num = 0;
    M = N-1;
    U = N-1;
    ub = (U+1)/2;
    k = M;
    for(i=1;i<=N;i++)
        chi[i]=0;
    nextp[1]=0; nextp[2]=1;chi[1]=1;
    Gen( 3, 0, 0, ub, 0, N-ub+1, 0, 0 );
    cout << an << ", ";
    }
return(0);
}
